using System;
using System.Collections.Generic;
using System.Text;
using Pizzaiolo.Core.Gameplay.Characters;
using Pizzaiolo.Core.Gameplay.Items;
using GarageGames.Torque.Util;

namespace Pizzaiolo.DynamicBalancing
{
    public class BalancedClient : Client
    {
        private BalanceConfig mBalanceConfig;
        private int currentLevel;
        private int currentSize;
        private int maxLevel;
        private int maxSize;
        private int scaleSize;
        private float currentValueInScaleSize;
        private float rangeOfLevel;
        
        public BalancedClient(Waiter waiter, float maxTip, float kindness)
            : base(waiter, maxTip, kindness)
        {
            this.mBalanceConfig = new BalanceConfig();
            this.currentLevel = 1; //Starts in the easiest level
            this.currentSize = 1; //Corresponds to the smalest pizza
            this.maxLevel = 5;
            this.maxSize = 5;
            this.scaleSize = 100; //the size of scale used in the jump level approach
            this.currentValueInScaleSize = this.scaleSize / this.maxLevel; //the level of the player in the scale
            this.rangeOfLevel = this.scaleSize / this.maxLevel; //the range of each level in the scale
        }

        public Pizza order(float chalengeLevel, bool isFirstTime)
        {
            Pizza pizza = null;

            if (!isFirstTime)
            {
                if (this.mBalanceConfig.approach == 0)
                {
                    pizza = this.nearLevelApproach(chalengeLevel);
                }
                else if (this.mBalanceConfig.approach == 1)
                {
                    pizza = this.jumpLevelApproach(chalengeLevel);
                }
            }
            else
            {
                //the easiest pizza of the game
                pizza = new Pizza("Mozzarella", Pizza.PizzaSize.Mini); 
            }

            return pizza;
        }

        private Pizza jumpLevelApproach(float chalengeLevel)
        {
            Pizza pizza = null;
            int sizeFactor = this.maxSize + 1;

            this.updateCurrentValueInScale(chalengeLevel, sizeFactor);
            this.translateCurrentValueInScaleToCurrentLevel();
          
            this.assertCorrectCurrentValues();
            
            pizza = this.choosePizza();
            return pizza;
        }

        private void translateCurrentValueInScaleToCurrentLevel()
        {
            if (this.currentValueInScaleSize <= this.rangeOfLevel)
            {
                this.currentLevel = 1;
            }
            else if(this.currentValueInScaleSize > this.rangeOfLevel && this.currentValueInScaleSize <= this.rangeOfLevel * 2)
            {
                this.currentLevel = 2;
            }
            else if (this.currentValueInScaleSize > this.rangeOfLevel * 2 && this.currentValueInScaleSize <= this.rangeOfLevel * 3)
            {
                this.currentLevel = 3;
            }
            else if (this.currentValueInScaleSize > this.rangeOfLevel * 3 && this.currentValueInScaleSize <= this.rangeOfLevel * 4)
            {
                this.currentLevel = 4;
            }
            else if (this.currentValueInScaleSize > this.rangeOfLevel * 4 && this.currentValueInScaleSize <= this.rangeOfLevel * 5)
            {
                this.currentLevel = 5;
            }
        }

        private void updateCurrentValueInScale(float chalengeLevel, int sizeFactor)
        {
            float randomFloat = TorqueUtil.GetRandomFloat(0,1);
            
            if (chalengeLevel <= 0.3)
            {
                this.currentValueInScaleSize = this.currentValueInScaleSize - (((1 - chalengeLevel) * this.rangeOfLevel) + ((sizeFactor - this.currentSize) * 2));
                this.currentSize--;
            }
            else if (chalengeLevel > 0.3 && chalengeLevel <= 0.5)
            {
                this.currentValueInScaleSize = this.currentValueInScaleSize - ((1 - chalengeLevel) * this.rangeOfLevel);

                if (randomFloat > chalengeLevel)
                {
                    this.currentSize--;
                }
            }
            else if (chalengeLevel > 0.5 && chalengeLevel <= 0.7)
            {
                this.currentValueInScaleSize = this.currentValueInScaleSize + (this.currentSize * 2);
            }
            else if (chalengeLevel > 0.7 && chalengeLevel <= 0.85)
            {
                this.currentValueInScaleSize = this.currentValueInScaleSize + (chalengeLevel * this.rangeOfLevel);
                
                if (randomFloat < chalengeLevel)
                {
                    this.currentSize++;
                }
            }
            else
            {
                this.currentValueInScaleSize = this.currentValueInScaleSize + ((chalengeLevel * this.rangeOfLevel) + (this.currentSize * 2));
                this.currentSize++;
            }
        }

        private Pizza nearLevelApproach(float chalengeLevel)
        {
            Pizza pizza = null;

            if (chalengeLevel <= 0.1)
            {
                this.currentLevel--;
                this.currentSize--;
            }
            else if (chalengeLevel > 0.1 && chalengeLevel <= 0.3)
            {
                this.currentLevel--;
            }
            else if (chalengeLevel > 0.3 && chalengeLevel < 0.5)
            {
                this.currentSize--;
            }
            else if (chalengeLevel >= 0.5 && chalengeLevel <= 0.65)
            {
                //do nothing
            }
            else if (chalengeLevel > 0.65 && chalengeLevel <= 0.75)
            {
                this.currentSize++;
            }
            else if (chalengeLevel > 0.75 && chalengeLevel < 0.9)
            {
                this.currentLevel++;
            }
            else
            {
                this.currentLevel++;
                this.currentSize++;
            }

            this.assertCorrectCurrentValues();

            pizza = this.choosePizza();

            return pizza;
        }

        private Pizza choosePizza()
        {

            Pizza pizza = null;

            if (this.mWaiter is BalancedWaiter)
            {
                List<string> menu = ((BalancedWaiter)this.mWaiter).viewMenu(this.currentLevel);
                int randomInt = TorqueUtil.GetRandomInt(0, menu.Count);
                string pizzaName = menu[randomInt];
                Pizza.PizzaSize size = this.converIntToPizzaSize(this.currentSize);
                pizza = new Pizza(pizzaName, size);
            }
            else
            {
                pizza = base.order();
            }
            
            return pizza;
        }

        private void assertCorrectCurrentValues()
        {
            if (this.currentSize < 1)
            {
                this.currentSize = 1;
            }
            
            if (this.currentSize > 5)
            {
                this.currentSize = 5;
            }

            if (this.currentLevel < 1)
            {
                this.currentLevel = 1;
            }

            if (this.currentLevel > 5)
            {
                this.currentLevel = 5;
            }
        }

        public Pizza.PizzaSize converIntToPizzaSize(int value)
        {   
            string name = Enum.GetName(typeof(Pizza.PizzaSize), value);
            Pizza.PizzaSize size = (Pizza.PizzaSize) Enum.Parse(typeof(Pizza.PizzaSize), name);
            return size;
        }


    }
}
